package com.power.sifa.approve.executor.impl;

import com.aventrix.jnanoid.jnanoid.NanoIdUtils;
import com.plf.common.domain.ResponseDTO;
import com.plf.common.domain.YesNo;
import com.plf.common.utils.PdfConvertUtil;
import com.plf.common.utils.StringUtil;
import com.plf.common.utils.WordUtil;
import com.plf.core.base.model.Ha_attachment;
import com.plf.core.base.service.Ha_attachmentService;
import com.power.flowable.api.ILog_limitscatFeign;
import com.power.flowable.api.IPersonalFeign;
import com.power.sifa.approve.model.*;
import com.power.sifa.approve.model.enumeration.*;
import com.power.sifa.approve.service.*;
import com.power.sifa.approve.thread.ThreadPoolUtil;
import com.power.sifa.base.model.enumeration.Tp_noticemsg;
import com.power.sifa.net.service.ApplyService;
import com.power.sifa.util.executor.AbstractPostExecutor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 受理校验环节
 */
@Component
@Slf4j
public class AdmreAuditAcceptCheck extends AbstractPostExecutor {

    // 用户id
    private String userid;
    // 环节分类标识
    private String category;
    // 用户名
    private String username;
    // 单位id
    private String sectionid;
    // 单位名称
    private String sectionname;
    // 部门id
    private String deptid;
    // 部门名称
    private String deptname;
    // 处理意见
    private String remark;
    // 行政区划
    private String adid;
    // 环节名称
    private String taskname;

    @Resource
    private Apl_mainService apl_mainService;
    @Resource
    private Apl_admre_auditService apl_admre_auditService;
    @Resource
    private Apl_admreviewService apl_admreviewService;
    @Resource
    private IPersonalFeign iPersonalFeign;
    @Resource
    private Apl_limit_replyService apl_limit_replyService;
    @Resource
    private Apl_limit_hearService apl_limit_hearService;
    @Resource
    private Apl_arrive_detailService apl_arrive_detailService;
    @Resource
    private BusinessApproveService businessApproveService;
    @Resource
    private ILog_limitscatFeign iLog_limitscatFeign;
    @Resource
    private ApplyService applyService;
    @Resource
    private Ha_attachmentService ha_attachmentService;
    @Resource
    private Aprv_process_materialsService aprv_process_materialsService;

    @Override
    public void init(Map<String, Object> initdata) {
        this.userid = (String) initdata.get("userid");
        this.category = (String) initdata.get("category");
        this.username = (String) initdata.get("username");
        this.sectionid = (String) initdata.get("sectionid");
        this.sectionname = (String) initdata.get("sectionname");
        this.deptid = (String) initdata.get("deptid");
        this.deptname = (String) initdata.get("deptname");
        this.remark = (String) initdata.get("remark");
        this.adid = (String) initdata.get("adid");
        this.taskname = (String) initdata.get("taskname");
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> execute() throws Exception {
        // 1. 查询子流程的表单数据
        Apl_main mainObj = apl_mainService.getById(super.applyid);
        Apl_admre_audit auditObj = this.apl_admre_auditService.getById(super.applyid);
        Apl_main faMainObj = this.apl_mainService.getById(auditObj.getApplyid());

        // 3. 修改业务主表状态为 已受理
        this.apl_admreviewService.updateStatus(auditObj.getApplyid(), St_admreview.ACCEPT);
        this.apl_admre_auditService.updateStatus(super.applyid, St_admreview.ACCEPT);

        // 4 修改主表状态为 已受理, 记录受理人信息
        faMainObj.setAcceptuserid(this.userid);
        faMainObj.setAcceptusername(this.username);
        faMainObj.setAcceptdeptid(this.deptid);
        faMainObj.setAcceptdeptname(this.deptname);
        faMainObj.setAcceptsectionid(this.sectionid);
        faMainObj.setAcceptsectionname(this.sectionname);
        faMainObj.setAcceptadid(this.adid);
        faMainObj.setStatus(St_apply.ACCEPT);
        this.apl_mainService.saveOrUpdate(faMainObj);

        // 2.1  如果需要市领导审批, 不自动生成审批表
        if (YesNo.NO == auditObj.getIscitymanager()) {
            // 2. 生成审批表
            this.generateDocuments(auditObj, mainObj.getFormid());
        }

        // 5. 先激活
        ResponseDTO activeRes = this.iPersonalFeign.activationProcess(faMainObj.getInstid());
        if (0 != activeRes.getCode()) {
            log.error("AdmreAuditAcceptCheck 激活父流程失败 -> msg[{}]", activeRes.getMsg());
            throw new RuntimeException("AdmreAuditAcceptCheck 激活父流程失败 -> " + activeRes.getMsg());
        }

        // 6. 往下再走一步
        String taskid = (String) activeRes.getData(); // 父流程任务id
        ResponseDTO axecRes = this.iPersonalFeign.processNext(faMainObj.getFormid(), faMainObj.getId(), taskid, userid, new HashMap());
        if (0 != axecRes.getCode()) {
            log.error("AdmreAuditAcceptCheck 完成父流程任务失败 -> msg[{}]", axecRes.getMsg());
            throw new RuntimeException("AdmreAuditAcceptCheck 完成父流程任务失败");
        }


        // 6.3 向赣政通发送一条被申请人通知书
//        this.apl_arrive_detailService.sendDiTodo(faMainObj, Tp_procmaterial.ADMRE_REPLY, this.userid, this.username);
        // 7. 生成被申请人答复时限记录
        {
            Calendar c = Calendar.getInstance();
            Apl_limit_reply replyObj = new Apl_limit_reply();
            replyObj.setId(faMainObj.getId());
            // 受理时间
            replyObj.setAcceptdate(c.getTime());
            // 告警时间加7天
            c.add(Calendar.DATE, 7);
            replyObj.setWarndate(c.getTime());
            // 截止日期加10天
            c.add(Calendar.DATE, 3);
            replyObj.setEnddate(c.getTime());
            this.apl_limit_replyService.saveOrUpdate(replyObj);
        }

        // 8. 生成审理时限记录
        {
            Calendar c = Calendar.getInstance();
            Apl_limit_hear hearObj = new Apl_limit_hear();
            hearObj.setId(faMainObj.getId());
            // 受理时间
            hearObj.setAcceptdate(c.getTime());
            // 告警时间加55天
            c.add(Calendar.DATE, 55);
            hearObj.setWarndate(c.getTime());
            // 截止日期加6天, 从第二天开始算, 故61天
            c.add(Calendar.DATE, 6);
            hearObj.setEnddate(c.getTime());
            this.apl_limit_hearService.saveOrUpdate(hearObj);
        }

        // 刷新文书日期
        this.businessApproveService.processEndedUpdatePreviewDoc(auditObj.getApplyid(), Tp_proctype.ACCEPT_ACCEPT, null);
        // 文书盖章
        this.businessApproveService.templateStamp(auditObj.getApplyid(), Tp_proctype.ACCEPT_ACCEPT);

        // 6.1.1 更新受理环节时限 scatid
        ThreadPoolUtil.executor.execute(() -> {
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                log.error("受理环节时限休眠10秒失败");
                e.printStackTrace();
            }
            // 更新办结时限信息
            // 6.1.2 受理通过后, 应该会更新成审理环节时限 scatid
            String scatid = (String) axecRes.getData();
            log.info("新环节scatid: {}", scatid);
            if (!StringUtil.isEmpty(scatid)) {
                Apl_main faMainObjNew = this.apl_mainService.getById(auditObj.getApplyid());
                // 6.1.3 如果更新了, 审理默认是两个月, 简易程序手动减去一个月时间
                Apl_admreview admreObj = this.apl_admreviewService.getById(auditObj.getApplyid());
                // 根据计算期满日期, 查询办结时限信息
                String endDate = this.businessApproveService.computeExpiryDate(admreObj.getProctype(), faMainObj.getAccepttime());
                log.info("更新主表期满日期 -> {}", endDate);
                // 更新主表期满日期
                SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
                SimpleDateFormat formatT = new SimpleDateFormat("yyyy年M月d日");
                try {
                    this.apl_admreviewService.updateQuedate(admreObj.getId(), formatT.format(format.parse(endDate)));
                } catch (ParseException e) {
                    log.error("主表期满日期格式化失败 -> {}", endDate);
                    e.printStackTrace();
                }
                ResponseDTO updateRes = this.iLog_limitscatFeign.updateById(faMainObjNew.getInstid(), scatid, endDate);
                if (0 != updateRes.getCode()) {
                    log.error("AdmreAuditAcceptCheck 根据环节组id更新截止日期失败 -> msg[{}]", updateRes.getMsg());
                    throw new RuntimeException("AdmreAuditAcceptCheck 根据环节组id更新截止日期失败");
                }
                this.apl_mainService.updateScatid(faMainObjNew.getInstid(), scatid);
                log.info("新环节成功scatid: {}, {}", scatid);
//                Apl_main faMainObjNew2 = this.apl_mainService.getById(auditObj.getApplyid());
//                log.info("faMainObjNew2 - {}", faMainObjNew2.getScatid());
            }
        });

        // 生成当前的送达通知
        this.apl_arrive_detailService.createSaveNotice(faMainObj.getId(), faMainObj.getAcceptcode(), faMainObj.getAcceptuserid(),
                7, faMainObj.getAcceptcode() + "已审批通过，请及时送达《行政复议申请受理通知书》", Tp_procmaterial.ADMRE_ACCEPT, Tp_noticemsg.ADMREIVEW_ARRIVE);
        this.apl_arrive_detailService.createSaveNotice(faMainObj.getId(), faMainObj.getAcceptcode(), faMainObj.getAcceptuserid(),
                7, faMainObj.getAcceptcode() + "已审批通过，请及时送达《行政复议答复通知书》", Tp_procmaterial.ADMRE_REPLY, Tp_noticemsg.ADMREIVEW_ARRIVE);
        // 发送赣政通通知
         this.apl_arrive_detailService.sendDiTodo(faMainObj, Tp_procmaterial.ADMRE_REPLY, this.userid, this.username);
        Map<String, Object> params = new HashMap<>(16);
        // 无需生成通知
        params.put("isAeliver", true);
        return params;
    }

    private void generateDocuments(Apl_admre_audit auditObj, String formid) throws Exception {
        // 2. 生成并上传文件
        Ha_attachment attachment;
        Map<String, Object> formData = this.applyService.formLoadField(formid, super.applyid);
        // 审批表意见和日期字段
        super.ApprovalField(formData);

        byte[] pdfByte;
        {
            WordUtil wordUtil = new WordUtil("AdmreAuditInCharge.docx");
            wordUtil.replaceTable(formData);
            try (OutputStream os = wordUtil.createWord();
                 InputStream is = new ByteArrayInputStream(((ByteArrayOutputStream) os).toByteArray())) {
                pdfByte = PdfConvertUtil.word2pdfWithFont(is);
                attachment = ha_attachmentService.upload(new ByteArrayInputStream(pdfByte), "案件受理审批表.pdf");
                log.info("AdmreAuditAcceptCheck 案件受理审批表生成并保存成功 -> {}", attachment.getId());
            } catch (Exception e) {
                log.error("AdmreAuditAcceptCheck 案件受理审批表生成并保存失败 ->  msg[{}]", e.getMessage());
                throw new RuntimeException("AdmreAuditAcceptCheck 案件受理审批表生成并保存失败 -> " + e.getMessage());
            }

            // 3. 保存审批系统文书, 只存父流程
            Aprv_process_materials docObj = new Aprv_process_materials(Tp_procmaterialEnum.ADMRE_APPROVE);
            docObj.setId(auditObj.getApplyid() + NanoIdUtils.randomNanoId());
            // 通知书类型枚举
            docObj.setMattype(Tp_procmaterial.ADMRE_APPROVE);
            docObj.setAttachid(attachment.getId());
            docObj.setCreateuserid(this.userid);
            docObj.setCreateuser(this.username);
            docObj.setCreatetime(new Date());
            docObj.setApplyid(auditObj.getApplyid());
            docObj.setType(Tp_proctype.ACCEPT_ACCEPT);
            docObj.setSonapplyid(auditObj.getId());
            this.aprv_process_materialsService.saveOrUpdate(docObj);
        }

        // 通知书补充字段
        Apl_admreview admreObj = this.apl_admreviewService.getById(auditObj.getApplyid());
        // 判断行为
        if (YesNo.YES == admreObj.getIsomission()) {
            formData.put("behavior", "不履行法定职责");
        } else {
            if (Tp_admpr.OTHER.getKey().equals(admreObj.getPrtype())) {
                formData.put("behavior", admreObj.getPrname());
            } else {
                formData.put("behavior", Tp_admpr.getByKey(admreObj.getPrtype()).getDescription());
            }
            // 拼接行政行为文号
            if (!StringUtil.isEmpty(admreObj.getPrcode())) {
                formData.put("prcode", "（编号：" + admreObj.getPrcode() + "）");
            } else {
                formData.put("prcode", "");
            }
        }
        // 提交时间
        Apl_main faMainObj = apl_mainService.getById(auditObj.getApplyid());
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        SimpleDateFormat formatT = new SimpleDateFormat("yyyy年M月d日");
        formData.put("subtime", formatT.format(format.parse(faMainObj.getSubtime())));
        // 当前时间
        formData.put("today", formatT.format(new Date()));
    }

}
